#include "err.hpp"
#include "sock.hpp"
#include <string>
#include <cstring>
#include <functional>
#include <sys/epoll.h>
#define arrsock_num 1024

namespace zxf
{
    static const int defaultport = 8888;
    static const int size = 128;
    static const int defaultvalue = -1;
    static const int defalultnum = 64;

    class epoll_server
    {
    public:
        using func_t = std::function<std::string(std::string &)>;
        epoll_server(uint16_t port = defaultport) : _port(port), _listensock(-1), _epfd(-1), _num(defalultnum), _events(nullptr)
        {
        }
        ~epoll_server()
        {
        }
        void initServer()
        {
            // 创建套接字
            _listensock = Sock::Socket();
            // 绑定点口号
            Sock::Bind(_listensock, _port);
            // 设置为监听状态
            Sock::Listen(_listensock);

            // 创建epoll实例
            _epfd = epoll_create(1);
            // 这个参数在大多数情况下被忽略，可以设置为任意值（建议大于 0）
            //  如果调用失败，它将返回 -1，并设置相应的错误码，可以通过全局变量 errno 获取具体的错误信息。
            if (_epfd == -1)
            {
                logMessage(FATAL, "epoll_create err , errno: %d, strerror: %s", errno, strerror(errno));
                exit(EPOLL_CREATE);
            }
            logMessage(NORMAL, "epoll_create success!!");

            // 将_listensock 添加到epoll实例中
            struct epoll_event event;
            event.data.fd = _listensock;
            event.events = EPOLLIN;
            int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &event);
            if (ret == 0)
            {
                logMessage(NORMAL, "epoll_ctl_add success, add_df: %d", _listensock);
            }
            else if (ret == -1)
            {
                logMessage(FATAL, "epoll_ctl_add err, add_df: %d", _listensock);
                exit(EPOLL_CTL);
            }
            else
            {
                logMessage(FATAL, "epoll_ctl_add err,  unknown error");
                exit(EPOLL_CTL);
            }

            // 申请就绪事件的空间
            _events = new struct epoll_event[_num];
            if (_events != nullptr)
            {
                logMessage(NORMAL, "new struct epoll_event[%d] success !!!", _num);
            }
        }

        void connectEvent()
        {
            // 获取一个链接
            int fd = Sock::Accept(_listensock, nullptr, nullptr);
            if (fd < 0)
            {
                logMessage(WARNING, "accept error");
                return;
            }

            // 将获取上来的文件描述符 添加到 epoll实例中
            struct epoll_event event;
            event.events = EPOLLIN;
            event.data.fd = fd;
            int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &event);
            if (ret == 0)
            {
                logMessage(NORMAL, "epoll_ctl_add success, add_df: %d", fd);
            }
            else if (ret == -1)
            {
                logMessage(FATAL, "epoll_ctl_add err, add_df: %d", fd);
                exit(EPOLL_CTL);
            }
            else
            {
                logMessage(FATAL, "epoll_ctl_add err,  unknown error");
                exit(EPOLL_CTL);
            }
        }
        void commonEvent(int sock, int event)
        {
            char buf[1024];
            int ret = recv(sock, buf, 1023, 0);
            if (ret > 0)
            {
                buf[ret] = 0;
                std::string request = buf;
                std::string response = _func(request);
                send(sock, response.c_str(), response.size(), 0);
            }
            else if (ret == 0)
            {
                // 链接关闭
                // 建议先从epoll移除，才close fd
                epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                close(sock);
                logMessage(NORMAL, "link close!!!  , number %d", sock);
            }
            else
            {
                // 出错了
                epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                close(sock);
                logMessage(ERROR, "recv error, code: %d, errstring: %s", errno, strerror(errno));
            }
        }

        void HandlerEvent(int num)
        {
            logMessage(DEBUG, "HandlerEvent in");
            for (int i = 0; i < num; i++)
            {
                uint32_t event = _events[i].events;
                int sock = _events[i].data.fd;

                if (sock == _listensock && event & EPOLLIN)
                {
                    connectEvent();
                }
                else if (sock != _listensock && event & EPOLLIN)
                {
                    commonEvent(sock, event);
                }
                else
                {
                    logMessage(WARNING, "unknown event!!");
                }
            }
        }

        void start(func_t func)
        {
            _func = func;
            // 循环检测 epoll实例中的事件是否就绪
            // 如果有事件发生调用HandlerEvent
            int timeout = -1;
            for (;;)
            {
                int ret = epoll_wait(_epfd, _events, _num, timeout);
                // 如果 epoll_wait 成功执行且有就绪的事件，则返回就绪事件的数量。
                // 如果没有任何事件就绪且超时时间到达（当指定了非负的 timeout 值），则返回 0。
                // 如果出现错误，例如调用被信号中断或传递了无效的参数，则返回 -1，并设置相应的错误码。可以通过全局变量 errno 获取具体的错误信息。
                if (ret == -1)
                {
                    logMessage(WARNING, "epoll_wait failed, code: %d, errstring: %s", errno, strerror(errno));
                    continue;
                }
                else if (ret == 0)
                {
                    logMessage(NORMAL, "timeout!!!");
                    continue;
                }
                else
                {
                    // 有事件就绪
                    logMessage(NORMAL, " hare event ready !! ");
                    HandlerEvent(ret);
                }
            }
        }

    private:
        uint16_t _port;              // 绑定的端口
        int _listensock;             // 监听文件描述符
        int _epfd;                   // epoll实例文件描述符
        struct epoll_event *_events; // 保存就绪事件
        int _num;                    // 规定epoll实例中的最大链接数量
        func_t _func;                // 回调函数
    };

}
